-----------------------------------------------------------------------------------
--|
--| Filename:     fpga_siggen.vhd
--|
--| Contents:     Entity          :  siggen
--|               Architecture    :  siggen_rtl
--|
--| Description:  The program generates sinewaves in a Xilinx 
--|               Spartan2E FPGA.  
--|               
--|
--| Author:       C. Talsma (derived from Xilinx AppNote XAPP154, Sept, 1999)
--|
--| Version:      1.0
--|
--| Revision History:
--|   Date:    
--|   By:    
--|   Change:
--|
--|
-----------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

-- Assign values infers the ROM for the design.  All ROM values are precalculated by hand
-- then inserted into this table.  The ROM values must be between 0 and 64k.

                          

entity siggen is
port(
    RESET    : in  std_logic;
    CLK50M   : in  std_logic;
	 SWCLK    : in  std_logic_vector (3 downto 0);
    SWWAVE   : in  std_logic_vector (1 downto 0);
    GEN_OUT  : out std_logic_vector (15 downto 0);
    CLK25M   : out std_logic;
    CLK12M   : out std_logic;
    CLK6M    : out std_logic;
    CLK3M    : out std_logic;
    CLK1M    : out std_logic;
    CLK780K  : out std_logic;
    CLK390K  : out std_logic;
    CLK195K  : out std_logic;
    CLK97K   : out std_logic;
    CLK48K   : out std_logic;
    CLK24K   : out std_logic;
    CLK12K   : out std_logic;
    CLK6K    : out std_logic;
    CLK3K    : out std_logic;
    CLK1_5K  : out std_logic;
	 RDCLK    : out std_logic
);
end siggen;

architecture siggen_rtl of siggen is

signal  count        : std_logic_vector (6 downto 0);
signal  CLK25M_int   : std_logic;
signal  CLK12M_int   : std_logic;
signal  CLK6M_int    : std_logic;
signal  CLK3M_int    : std_logic;
signal  CLK1M_int    : std_logic;
signal  CLK780K_int  : std_logic;
signal  CLK390K_int  : std_logic;
signal  CLK195K_int  : std_logic;
signal  CLK97K_int   : std_logic; 
signal  CLK48K_int   : std_logic; 
signal  CLK24K_int   : std_logic; 
signal  CLK12K_int   : std_logic; 
signal  CLK6K_int    : std_logic; 
signal  CLK3K_int    : std_logic; 
signal  CLK1_5K_int  : std_logic; 
signal  RDCLK_int    : std_logic;

begin

clk25m_gen : process (CLK50M, RESET)
begin
    if RESET = '1' then
        CLK25M_int   <= '0';
    elsif rising_edge (CLK50M) then
        CLK25M_int <= not CLK25M_int;
    end if;
end process clk25m_gen;


clk12m_gen : process (CLK25M_int, RESET)
begin
    if RESET = '1' then
        CLK12M_int   <= '0';
    elsif rising_edge (CLK25M_int) then
        CLK12M_int <= not CLK12M_int;
    end if;
end process clk12m_gen;


clk6m_gen : process (CLK12M_int, RESET)
begin
    if RESET = '1' then
        CLK6M_int <= '0';
    elsif rising_edge (CLK12M_int) then
        CLK6M_int <= not CLK6M_int;
    end if;
end process clk6m_gen;


clk3m_gen : process (CLK6M_int, RESET)
begin
    if RESET = '1' then
        CLK3M_int <= '0';
    elsif rising_edge (CLK6M_int) then
        CLK3M_int <= not CLK3M_int;
    end if;
end process clk3m_gen;


clk1m_gen : process (CLK3M_int, RESET)
begin
    if RESET = '1' then
        CLK1M_int   <= '0';
    elsif rising_edge (CLK3M_int) then
        CLK1M_int <= not CLK1M_int;
    end if;
end process clk1m_gen;


clk780k_gen : process (CLK1M_int, RESET)
begin
    if RESET = '1' then
        CLK780K_int  <= '0';
    elsif rising_edge (CLK1M_int) then
        CLK780K_int <= not CLK780K_int;
    end if;
end process clk780k_gen;

clk390k_gen : process (CLK780K_int, RESET)
begin
    if RESET = '1' then
        CLK390K_int  <= '0';
    elsif rising_edge (CLK780K_int) then
        CLK390K_int <= not CLK390K_int;
    end if;
end process clk390k_gen;

clk195k_gen : process (CLK390K_int, RESET)
begin
    if RESET = '1' then
        CLK195K_int  <= '0';
    elsif rising_edge (CLK390K_int) then
        CLK195K_int <= not CLK195K_int;
    end if;
end process clk195k_gen;


clk97k_gen : process (CLK195K_int, RESET)
begin
    if RESET = '1' then
        CLK97K_int  <= '0';
    elsif rising_edge (CLK195K_int) then
        CLK97K_int <= not CLK97K_int;
    end if;
end process clk97k_gen;


clk48k_gen : process (CLK97K_int, RESET)
begin
    if RESET = '1' then
        CLK48K_int  <= '0';
    elsif rising_edge (CLK97K_int) then
        CLK48K_int <= not CLK48K_int;
    end if;
end process clk48k_gen;


clk24k_gen : process (CLK48K_int, RESET)
begin
    if RESET = '1' then
        CLK24K_int  <= '0';
    elsif rising_edge (CLK48K_int) then
        CLK24K_int <= not CLK24K_int;
    end if;
end process clk24k_gen;


clk12k_gen : process (CLK24K_int, RESET)
begin
    if RESET = '1' then
        CLK12K_int  <= '0';
    elsif rising_edge (CLK24K_int) then
        CLK12K_int <= not CLK12K_int;
    end if;
end process clk12k_gen;


clk6k_gen : process (CLK12K_int, RESET)
begin
    if RESET = '1' then
        CLK6K_int  <= '0';
    elsif rising_edge (CLK12K_int) then
        CLK6K_int <= not CLK6K_int;
    end if;
end process clk6k_gen;

clk3k_gen : process (CLK6K_int, RESET)
begin
    if RESET = '1' then
        CLK3K_int  <= '0';
    elsif rising_edge (CLK6K_int) then
        CLK3K_int <= not CLK3K_int;
    end if;
end process clk3k_gen;

clk1_5k_gen : process (CLK3K_int, RESET)
begin
    if RESET = '1' then
        CLK1_5K_int  <= '0';
    elsif rising_edge (CLK3K_int) then
        CLK1_5K_int <= not CLK1_5K_int;
    end if;
end process clk1_5k_gen;


sel_clock : process (SWCLK, CLK50M)
begin
    if rising_edge (CLK50M) then
        case SWCLK is
            when "0000" => RDCLK_int <= clk1_5k_int;
            when "0001" => RDCLK_int <= clk3k_int;
            when "0010" => RDCLK_int <= clk6k_int;
            when "0011" => RDCLK_int <= clk12k_int;
            when "0100" => RDCLK_int <= clk24k_int;
            when "0101" => RDCLK_int <= clk48k_int;
            when "0110" => RDCLK_int <= clk97k_int;
            when "0111" => RDCLK_int <= clk195k_int;
            when "1000" => RDCLK_int <= clk390k_int;
            when "1001" => RDCLK_int <= clk780k_int;
            when "1010" => RDCLK_int <= clk1m_int;
            when "1011" => RDCLK_int <= clk3m_int;
            when "1100" => RDCLK_int <= clk6m_int;
            when "1101" => RDCLK_int <= clk12m_int;
            when "1110" => RDCLK_int <= clk25m_int;
            when "1111" => RDCLK_int <= clk50m;
            when others => null;
        end case;
    end if;
end process sel_clock;



set_count : process (RDCLK_int, RESET)
begin
    if RESET = '1' then
        count <= "0000000";
    elsif rising_edge (RDCLK_int) then
        count <= count + '1';
    end if;
end process set_count;
     
data_gen : process (RDCLK_int, RESET)

type mem is array (0 to 127) of integer range 0 to 2**16 -1;

constant sinusoid : mem := (32768, 34376, 35980, 37577, 39161, 40730, 42281, 43808, 
                            45308, 46779, 48215, 49615, 50973, 52288, 53556, 54774,
                            55939, 57048, 58099, 59088, 60014, 60875, 61667, 62390,
                            63042, 63621, 64126, 64554, 64907, 65182, 65379, 65497,
                            65535, 65497, 65379, 65182, 64907, 64554, 64126, 63621,
                            63045, 62390, 61667, 60875, 60014, 59088, 58099, 57048,
                            55939, 54774, 53556, 52288, 50973, 49615, 48215, 46779,
                            45308, 43808, 42281, 40730, 39161, 37577, 35980, 34376,
                            32768, 31161, 29557, 27960, 26376, 24807, 23256, 21729,
                            20229, 18758, 17322, 15922, 14564, 13249, 11981, 10763,
                             9598,  8489,  7438,  6449,  5523,  4662,  3870,  3147,
                             2495,  1916,  1411,   983,   630,   355,   158,    40,
                                0,    40,   158,   355,   630,   983,  1411,  1916,
                             2495,  3147,  3870,  4662,  5523,  6449,  7438,  8489,
                             9598, 10763, 11981, 13249, 14564, 15922, 17322, 18758,
                            20229, 21729, 23256, 24807, 26376, 27960, 29557, 31161);
                            
constant triangle : mem := (32768, 33792, 34816, 35840, 36864, 37888, 38912, 39936,
                            40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128,
                            49152, 50176, 51200, 52224, 53248, 54272, 55296, 56320,
                            57344, 58368, 59392, 60416, 61440, 62464, 63488, 64512,
                            65535, 64512, 63488, 62464, 61440, 60416, 59392, 58368,
                            57344, 56320, 55296, 54272, 53248, 52224, 51200, 50176, 
                            49152, 48128, 47104, 46080, 45056, 44032, 43008, 41984, 
                            40960, 39936, 38912, 37888, 36864, 35840, 34816, 33792,
                            32768, 31744, 30720, 29696, 28672, 27648, 26624, 25600,
                            24576, 23552, 22528, 21504, 20480, 19456, 18432, 17408,
                            16384, 15360, 14336, 13312, 12288, 11264, 10240,  9216,
                             8192,  7168,  6144,  5120,  4096,  3072,  2048,  1024,
                                0,  1024,  2048,  3072,  4096,  5120,  6144,  7168,
                             8192,  9216, 10240, 11264, 12288, 13312, 14336, 15360,
                            16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552,
                            24576, 25600, 26624, 27648, 28672, 29696, 30720, 31744);


constant square  : mem  := (32768, 39321, 45875, 52428, 58982, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
                            65535, 65535, 65535, 65535, 58982, 52428, 45875, 39321,
                            32768, 26214, 19661, 13107,  6554,     0,     0,     0,
                                0,     0,     0,     0,     0,     0,     0,     0,
                                0,     0,     0,     0,     0,     0,     0,     0,
                                0,     0,     0,     0,     0,     0,     0,     0,
                                0,     0,     0,     0,     0,     0,     0,     0,
                                0,     0,     0,     0,     0,     0,     0,     0,
                                0,     0,     0,     0,     0,     0,     0,     0,
                                0,     0,     0,     0,  6554, 13107, 19661, 26214);

begin

  if RESET = '1' then 
      GEN_OUT <= "0000000000000000";
  elsif rising_edge (RDCLK_int) then
      case SWWAVE is
         when "00" => 
           GEN_OUT <= conv_std_logic_vector(sinusoid(conv_integer(count(6 downto 0))), 127);
         when "01" =>
           GEN_OUT <= conv_std_logic_vector(triangle(conv_integer(count(6 downto 0))), 127);
         when "10" =>
           GEN_OUT <= conv_std_logic_vector(square(conv_integer(count(6 downto 0))), 127);
         when others =>
           GEN_OUT <= conv_std_logic_vector(sinusoid(conv_integer(count(6 downto 0))), 127);
     end case;
   end if;
end process data_gen; 



CLK25M  <= CLK25M_int;
CLK12M  <= CLK12M_int;
CLK6M   <= CLK6M_int;
CLK3M   <= CLK3M_int;
CLK1M   <= CLK1M_int;
CLK780K <= CLK780K_int;
CLK390K <= CLK390K_int;
CLK195K <= CLK195K_int;
CLK97K  <= CLK97K_int;
CLK48K  <= CLK48K_int;
CLK24K  <= CLK24K_int;
CLK12K  <= CLK12K_int;
CLK6K   <= CLK6K_int;
CLK3K   <= CLK3K_int;
CLK1_5K <= CLK1_5K_int;
RDCLK   <= RDCLK_int;

  
end siggen_rtl;                     













